package com.lecyon.farm.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.lecyon.farm.base.BaseRequestPageVo;
import com.lecyon.farm.base.BaseRequestVo;
import com.lecyon.farm.base.BaseResponse;
import com.lecyon.farm.base.RestResponse;
import com.lecyon.farm.common.CommonService;
import com.lecyon.farm.common.constant.CommonConstant;
import com.lecyon.farm.common.constant.FarmSysConstant;
import com.lecyon.farm.common.enums.ExcelFileEnum;
import com.lecyon.farm.common.enums.SysRoleEnum;
import com.lecyon.farm.common.exception.FarmException;
import com.lecyon.farm.entity.*;
import com.lecyon.farm.mapper.FmWorkMapper;
import com.lecyon.farm.service.*;
import com.lecyon.farm.util.RedisUtils;
import com.lecyon.farm.util.ResultUtil;
import com.lecyon.farm.util.StringHelper;
import com.lecyon.farm.util.ValidateUtils;
import com.lecyon.farm.vo.add.AddFmWorkVo;
import com.lecyon.farm.vo.copy.DuplicateVo;
import com.lecyon.farm.vo.data.FmWorkStatisticByAreaVo;
import com.lecyon.farm.vo.export.ExportFmWorkVo;
import com.lecyon.farm.vo.modify.ModifyFmWorkVo;
import com.lecyon.farm.vo.query.QueryFmWorkVo;
import com.lecyon.farm.vo.request.IdsVo;
import com.lecyon.farm.vo.request.TotalWorkQuantity;
import com.lecyon.farm.vo.status.StatusVo;
import com.lecyon.farm.vo.view.FmWorkVo;
import com.lecyon.farm.vo.view.StatisticByAreaAndWorkTypePerYear;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.PostConstruct;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 农机作业历史 服务实现类
 *
 * @author YaoZheng
 * @since 2020-04-02
 */
@Service
@Validated
public class FmWorkServiceImpl extends ServiceImpl<FmWorkMapper, FmWork> implements IFmWorkService {

    private static final Logger LOG = LoggerFactory.getLogger(FmWorkServiceImpl.class);

    private FmWorkMapper mapper;

    private IJsSysOfficeService jsSysOfficeService;

    private IJsSysEmployeeService jsSysEmployeeService;

    private IFmCarService fmCarService;

    private IExcelService excelService;

    private CommonService commonService;

    private RedisUtils redisUtils;

    private List<OrderItem> orderItemList = new ArrayList();

    /**
     * 新增农机作业
     *
     * @param addVo 新增农机作业对象
     * @return 新增记录的id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResponse<Long> add(AddFmWorkVo addVo) {
        RestResponse<Long> result = new RestResponse<>();
        //有效性校验
        //必填项校验
        //重复性校验
        FmWork entity = new FmWork();
        BeanUtils.copyProperties(addVo, entity);
        //逻辑校验
        result = logicValidate(entity, result);
        if (!result.isSuccess()) {
            return result;
        }
        boolean flag = entity.insert();
        if (!flag) {
            LOG.warn("FmWork add method invoke failed. vo :{}", addVo.toString());
            return ResultUtil.error(null, CommonConstant.EX_DB_INSERT_ERROR, "新增失败！");
        }
        LOG.info("FmWork add method invoke success. vo : {}", addVo.toString());
        return ResultUtil.success(null, entity.getId());
    }

    @Override
    public RestResponse<Long> cumulative(AddFmWorkVo addVo) {
        return null;
    }

    /**
     * 编辑农机作业
     *
     * @param modifyVo 编辑对象
     * @return RestResponse
     */
    @Override
    public RestResponse<Long> modify(ModifyFmWorkVo modifyVo) {
        //有效性校验
        //必填项校验
        RestResponse<Long> result = new RestResponse<>();
        FmWork entity = new FmWork();
        BeanUtils.copyProperties(modifyVo, entity);
        //逻辑校验
        result = logicValidate(entity, result);
        if (!result.isSuccess()) {
            return result;
        }
        boolean flag = entity.updateById();
        if (!flag) {
            LOG.warn("FmWork modify method invoke failed. vo :{}", modifyVo.toString());
            return ResultUtil.error(null, CommonConstant.EX_DB_UPDATE_ERROR, "编辑失败！");
        }
        LOG.info("FmWork modify method invoke success. vo : {}", modifyVo.toString());
        return ResultUtil.success(null, entity.getId());
    }

    /**
     * 复制农机作业
     *
     * @param duplicateVo 复制对象Vo
     * @return
     */
    @Override
    public RestResponse<Long> duplicate(DuplicateVo duplicateVo) {
        return null;
    }

    @Override
    public BaseResponse changeStatus(StatusVo statusVo) {
        return null;
    }

    /**
     * 查看记录
     *
     * @param vo 查询条件(id)
     * @return 查询结果
     */
    @Override
    public RestResponse<FmWorkVo> get(QueryFmWorkVo vo) {
        RestResponse<FmWorkVo> result = new RestResponse<>();
        if (ValidateUtils.isNullOrEmpty(vo) || StringHelper.isEmpty(vo.getId())) {
            return ResultUtil.error(result, CommonConstant.EX_FORM_VALIDATE_REQUIRED, "缺少必要的查询条件！");
        }
        FmWorkVo resultVo = mapper.selectByPrimaryKey(vo);
        if (ValidateUtils.isNullOrEmpty(resultVo)) {
            return ResultUtil.error(result, CommonConstant.EX_DB_SELECT_MISS, "未找到符合条件的记录！");
        }
        return ResultUtil.success(result, resultVo);
    }

    /**
     * 查询列表
     * 引入数据隔离
     *
     * @param vo 查询条件(包含分页）
     * @return 查询结果
     */
    @Override
    public RestResponse<Page<FmWorkVo>> getPageList(BaseRequestPageVo<QueryFmWorkVo> vo) {
        RestResponse<Page<FmWorkVo>> result = new RestResponse<>();
        String token = vo.getUserToken();
        JsSysUser sysUser = commonService.findUserByToken(token);
        if (ValidateUtils.isNullOrEmpty(sysUser)) {
            return ResultUtil.error(null, CommonConstant.ASSOCIATED_DATA_MISS, "找不到登录用户相关数据");
        }
        String userCode = sysUser.getUserCode();
        QueryFmWorkVo queryCondition = vo.getEntity(QueryFmWorkVo.class);
        if (StringHelper.isEmpty(queryCondition.getType())) {
            log.warn("Method getTotalDataList invoked. But necessary condition is missed. 未指定作业类型");
            return ResultUtil.error(result, CommonConstant.EX_FORM_VALIDATE_REQUIRED, "未指定作业类型");
        }
        String officeCode = null;
        JsSysEmployee jsSysEmployee = jsSysEmployeeService.getById(userCode);
        if (ValidateUtils.isNotNullOrEmpty(jsSysEmployee)) {
            officeCode = jsSysEmployee.getOfficeCode();
        }

        QueryWrapper<FmCar> fmCarQueryWrapper = new QueryWrapper<>();
        Set<String> fmCarIdSet = Sets.newTreeSet();
        if (SysRoleEnum.MASTER.getLevel().equals(sysUser.getSign())) {
            // 机构管理员 可以看到所辖区域内所有相关信息
            // GR代表个人用户
            String specialOfficeCode = "GR";
            if (StringHelper.isNotEmpty(officeCode) && !specialOfficeCode.equals(officeCode)) {
                JsSysOffice jsSysOffice = jsSysOfficeService.getById(officeCode);
                if (ValidateUtils.isNotNullOrEmpty(jsSysOffice) && StringHelper.isNotEmpty(jsSysOffice.getParentCodes())) {
                    String parentCodes = jsSysOffice.getParentCodes();
                    if (parentCodes.contains(CommonConstant.HARDWARE_RESPONSE_SPLIT_STR)) {
                        String[] parentCode = parentCodes.split(CommonConstant.HARDWARE_RESPONSE_SPLIT_STR);
                        int codeLength = parentCode.length;
                        switch (codeLength) {
                            case 1:
                                // 省级机构
                                queryCondition.setProvince(officeCode);
                                fmCarQueryWrapper.eq("province", officeCode);
                                break;
                            case 2:
                                // 市级机构
                                queryCondition.setProvince(parentCode[1]);
                                queryCondition.setCity(officeCode);
                                fmCarQueryWrapper.eq("province", parentCode[1]).eq("city", officeCode);
                                break;
                            case 3:
                                // 区县机构
                                queryCondition.setProvince(parentCode[1]);
                                queryCondition.setCity(parentCode[2]);
                                queryCondition.setCounty(officeCode);
                                fmCarQueryWrapper.eq("province", parentCode[1]).eq("city", parentCode[2])
                                        .eq("county", officeCode);
                                break;
                            default:
                                // 乡镇一级机构
                                queryCondition.setProvince(parentCode[1]);
                                queryCondition.setCity(parentCode[2]);
                                queryCondition.setCounty(parentCode[3]);
                                queryCondition.setTowns(officeCode);
                                fmCarQueryWrapper.eq("province", parentCode[1]).eq("city", parentCode[2])
                                        .eq("county", parentCode[3]).eq("towns", officeCode);
                                break;
                        }
                    }
                }
            }
            List<FmCar> fmCarList = fmCarService.list(fmCarQueryWrapper);
            if (CollectionUtils.isNotEmpty(fmCarList)) {
                fmCarList.stream().forEach(item -> fmCarIdSet.add(item.getCarId()));
            }

        } else if (SysRoleEnum.ADMIN.getLevel().equals(sysUser.getSign())) {
            // 合作社管理员 可以看到该合作社所有相关信息
            queryCondition.setCooperationId(jsSysEmployee.getOfficeCode());
        } else if (SysRoleEnum.USER.getLevel().equals(sysUser.getSign())) {
            // 个人用户 可以看到个人上传的所有信息
            queryCondition.setUserId(sysUser.getUserCode());
        } else if (SysRoleEnum.HOST.getLevel().equals(sysUser.getSign())) {
            // 主机用户 可以看到该主机上传的所有信息
            queryCondition.setCarId(sysUser.getWxOpenid());
        }

        Page<FmWorkVo> page = new Page<>(vo.getPageNum(), vo.getPageSize());
        String redisTableName = FarmSysConstant.REDIS_KEY_DAILY_DATA;
        boolean redisFlag = false;
        boolean quickSearchFlag = queryCondition.isQuickSearch();
        String type = queryCondition.getType();
        if (quickSearchFlag) {
            redisFlag = redisUtils.hHasKey(redisTableName, type);
        }
        if (redisFlag) {
            List<FmWorkVo> dailyDataResult = (List<FmWorkVo>) redisUtils.hGet(redisTableName, type);
            List<FmWorkVo> resultList;
            List<FmWorkVo> tempResultList = Lists.newLinkedList();
            if (CollectionUtils.isNotEmpty(dailyDataResult)) {
                if (StringHelper.isNotEmpty(queryCondition.getCarId()) || StringHelper.isNotEmpty(queryCondition.getCarOwner()) || StringHelper.isNotEmpty(queryCondition.getCarOwnerPhone())) {
                    String carId = queryCondition.getCarId();
                    String carOwner = queryCondition.getCarOwner();
                    String carOwnerPhone = queryCondition.getCarOwnerPhone();
                    LocalDateTime beginTime = null;
                    LocalDateTime endTime = null;
                    if (ValidateUtils.isNotNullOrEmpty(queryCondition.getBeginDate())) {
                        beginTime = LocalDateTime.of(queryCondition.getBeginDate(), LocalTime.MIN);
                    }
                    if (ValidateUtils.isNotNullOrEmpty(queryCondition.getEndDate())) {
                        endTime = LocalDateTime.of(queryCondition.getEndDate(), LocalTime.MAX);
                    }
                    LocalDate workDate;
                    LocalDateTime workDateTime = null;
                    for (FmWorkVo tempData : dailyDataResult) {
                        if (StringHelper.isEmpty(carId) || !carId.equals(tempData.getCarId())) {
                            continue;
                        }
                        if (StringHelper.isEmpty(carOwner) || !carOwner.equals(tempData.getCarOwner())) {
                            continue;
                        }
                        if (StringHelper.isEmpty(carOwnerPhone) || !carOwnerPhone.equals(tempData.getCarOwnerPhone())) {
                            continue;
                        }
                        if (CollectionUtils.isNotEmpty(fmCarIdSet) && !fmCarIdSet.contains(tempData.getCarId())) {
                            continue;
                        }
                        if (ValidateUtils.isNotNullOrEmpty(tempData.getWorkDate())) {
                            workDate = tempData.getWorkDate();
                            workDateTime = LocalDateTime.of(workDate, LocalTime.MIN);
                            if (ValidateUtils.isNotNullOrEmpty(beginTime) && beginTime.isAfter(workDateTime)) {
                                continue;
                            }
                            if (ValidateUtils.isNotNullOrEmpty(endTime) && endTime.isBefore(workDateTime)) {
                                continue;
                            }
                        }
                        tempResultList.add(tempData);
                    }
                } else {
                    tempResultList.addAll(dailyDataResult);
                }
            }
            int startIndex, endIndex;
            int pageNum = vo.getPageNum();
            int pageSize = vo.getPageSize();
            startIndex = pageSize * (pageNum - 1);
            endIndex = startIndex + pageSize;
            if (endIndex >= tempResultList.size()) {
                endIndex = tempResultList.size();
            }
            resultList = tempResultList.subList(startIndex, endIndex);
            page.setTotal(tempResultList.size());
            page.setRecords(resultList);
        } else {
            if (CollectionUtils.isNotEmpty(vo.getOrders())) {
                List<OrderItem> orderItemList = CommonService.batchAddPrefix4OrderColumn(vo.getOrders());
                page.setOrders(orderItemList);
            } else {
                orderItemList.add(OrderItem.desc("mt.work_date"));
                page.setOrders(orderItemList);
            }
            page = mapper.selectByPage(page, queryCondition);
        }
        return ResultUtil.success(result, page);
    }

    /**
     * 查询日报列表
     *
     * @param vo
     * @return
     */
    @Override
    public RestResponse<Page<FmWorkVo>> dailyDataList(BaseRequestPageVo<QueryFmWorkVo> vo) {
        RestResponse<Page<FmWorkVo>> result = new RestResponse<>();
        RestResponse<Page<FmWorkVo>> transportResult = getPageList(vo);
        if (!transportResult.isSuccess()) {
            LOG.error("查询日报列表失败！");
            return ResultUtil.error(result, transportResult.getCode(), transportResult.getErrorMessage());
        }
        if (ValidateUtils.isNullOrEmpty(transportResult.getData())) {
            return transportResult;
        }
        Page<FmWorkVo> resultPage = transportResult.getData();
        List<FmWorkVo> resultList = resultPage.getRecords();
        if (CollectionUtils.isNotEmpty(resultList)) {
            for (FmWorkVo bean : resultList) {
                bean.setQualifiedLandarea(String.format("%.2f", Double.parseDouble(bean.getQualifiedLandarea()) - Double.parseDouble(bean.getRepeatRate())));
                bean.setSeedPerMu(String.format("%.2f", (Double.parseDouble(bean.getSeed()) / Double.parseDouble(bean.getWorkLandarea()))));
            }
            resultPage.setRecords(resultList);
        }
        return ResultUtil.success(result, resultPage);
    }

    /**
     * 获取日报列表并加载到缓存中
     * 定时轮询
     *
     * @return 查询结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Scheduled(fixedRate = FarmSysConstant.SCHEDULE_FIX_RATE)
    public BaseResponse reloadDailyDataList() {
        LOG.info("定时任务{}启动", "reloadDailyDataList");
        QueryFmWorkVo queryCondition = new QueryFmWorkVo();
        List<FmWorkVo> dailyDataResult;
        String[] types = FarmSysConstant.SYS_JOB_TYPE;
        String tableName = FarmSysConstant.REDIS_KEY_DAILY_DATA;
        boolean flag;
        // 日报一般是查询前一天的 当天的日报需要第二天凌晨才生成
        LocalDate currentDate = LocalDate.now(ZoneId.systemDefault()).plusDays(-1);
        for (String type : types) {
            queryCondition.setType(type);
            queryCondition.setBeginDate(currentDate);
            queryCondition.setEndDate(currentDate);
            dailyDataResult = mapper.selectByCondition(queryCondition);
            flag = redisUtils.hHasKey(tableName, type);
            if (flag) {
                //删除原有list
                redisUtils.hDel(tableName, type);
            }
            flag = redisUtils.hSet(tableName, type, dailyDataResult);
            if (!flag) {
                throw new FarmException(CommonConstant.EX_DB_REDIS_ERROR, "缓存到Redis时发生异常");
            }
        }
        LOG.info("定时任务{}完成", "reloadDailyDataList");
        return ResultUtil.success();
    }

    /**
     * 查询按区域统计作业
     *
     * @param vo
     * @return
     */
    @Override
    public List<FmWorkStatisticByAreaVo> selectStatisticByArea(QueryFmWorkVo vo) {
        List<FmWorkStatisticByAreaVo> result;
        QueryFmWorkVo queryCondition = vo;
        // 按区域统计 省 市 县 的代码只能有一个不为空
        if (StringHelper.isNotEmpty(queryCondition.getProvince())) {
            result = mapper.selectStatisticGroupByCity(queryCondition);
        } else if (StringHelper.isNotEmpty(queryCondition.getCity())) {
            result = mapper.selectStatisticGroupByCounty(queryCondition);
        } else if (StringHelper.isNotEmpty(queryCondition.getCounty())) {
            result = mapper.selectStatisticGroupByTowns(queryCondition);
        } else {
            result = mapper.selectStatisticGroupByProvince(queryCondition);
        }
        return result;
    }

    /**
     * 查询按区域统计作业(仅昨天)
     *
     * @param officeCode
     * @return
     */
    @Override
    public RestResponse<BigDecimal> getTotalWorkQuantityByAreaYesterday(String officeCode) {
        RestResponse<BigDecimal> result = new RestResponse<>();
        BigDecimal data = new BigDecimal("0");
        boolean redisFlag = redisUtils.hHasKey(FarmSysConstant.REDIS_KEY_FM_WORK_TOTAL_YESTERDAY, officeCode);
        if (redisFlag) {
            Object jsonStr = redisUtils.hGet(FarmSysConstant.REDIS_KEY_FM_WORK_TOTAL_YESTERDAY, officeCode);
            data = new BigDecimal(jsonStr.toString());
        }
        return ResultUtil.success(result, data);
    }

    /**
     * 遍历区域统计昨日作业量
     *
     * @return
     */
    @Scheduled(fixedRate = FarmSysConstant.SCHEDULE_FIX_RATE_PER_DAY)
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse statisticTotalFmWorkYesterday() {
        List<JsSysOffice> jsSysOfficeList = jsSysOfficeService.list();
        if (CollectionUtils.isEmpty(jsSysOfficeList)) {
            return ResultUtil.success();
        }
        boolean redisFlag;
        QueryWrapper<FmCar> fmCarQueryWrapper;
        QueryWrapper<FmWork> fmWorkQueryWrapper;
        String officeCode, officeType;
        List<FmCar> fmCarList;
        Set<String> fmCarIdSet = Sets.newTreeSet();
        List<FmWork> fmWorkList;
        BigDecimal totalWorkQuantity;
        BigDecimal eachWorkQuantity;
        LocalDate yesterday = LocalDate.now(ZoneId.systemDefault()).plusDays(-1);
        LocalDateTime queryBeginTime = LocalDateTime.of(yesterday, LocalTime.MIN);
        LocalDateTime queryEndTime = LocalDateTime.of(yesterday, LocalTime.MAX);
        for (JsSysOffice jsSysOffice : jsSysOfficeList) {
            if (StringHelper.isEmpty(jsSysOffice.getOfficeCode()) || StringHelper.isEmpty(jsSysOffice.getOfficeType())) {
                continue;
            }
            fmCarIdSet.clear();
            totalWorkQuantity = new BigDecimal("0");
            fmCarQueryWrapper = new QueryWrapper<>();
            fmWorkQueryWrapper = new QueryWrapper<>();
            fmWorkQueryWrapper.between("work_date", queryBeginTime, queryEndTime);
            officeCode = jsSysOffice.getOfficeCode();
            officeType = jsSysOffice.getOfficeType();
            switch (officeType) {
                case "1":
                    //省级机构区域
                    fmCarQueryWrapper.eq("province", officeCode);
                    break;
                case "2":
                    //市级机构区域
                    fmCarQueryWrapper.eq("city", officeCode);
                    break;
                case "3":
                    //区县级机构区域
                    fmCarQueryWrapper.eq("county", officeCode);
                    break;
                default:
                    //乡镇级机构区域
                    fmCarQueryWrapper.eq("towns", officeCode);
                    break;
            }
            fmCarList = fmCarService.list(fmCarQueryWrapper);
            if (CollectionUtils.isEmpty(fmCarList)) {
                continue;
            }
            fmCarList.stream().forEach(fmCar -> {
                if (StringHelper.isNotEmpty(fmCar.getCarId())) {
                    fmCarIdSet.add(fmCar.getCarId());
                }
            });
            if (CollectionUtils.isEmpty(fmCarIdSet)) {
                continue;
            }
            fmWorkQueryWrapper.in("car_id", fmCarIdSet);
            fmWorkList = list(fmWorkQueryWrapper);
            if (CollectionUtils.isEmpty(fmWorkList)) {
                continue;
            }
            for (FmWork fmWork : fmWorkList) {
                if (StringHelper.isEmpty(fmWork.getQualifiedLandarea())) {
                    continue;
                }
                eachWorkQuantity = new BigDecimal(fmWork.getQualifiedLandarea());
                totalWorkQuantity = totalWorkQuantity.add(eachWorkQuantity);
            }
            redisFlag = redisUtils.hSet(FarmSysConstant.REDIS_KEY_FM_WORK_TOTAL_YESTERDAY, officeCode, totalWorkQuantity);
            if (!redisFlag) {
                throw new FarmException(CommonConstant.EX_DB_REDIS_ERROR, "系统缓存异常");
            }
        }
        return ResultUtil.success();
    }

    /**
     * 查询列表
     *
     * @param vo 查询条件（不含分页信息）
     * @return 查询结果
     */
    @Override
    public RestResponse<List<FmWorkVo>> getList(BaseRequestVo<QueryFmWorkVo> vo) {
        RestResponse<List<FmWorkVo>> result = new RestResponse<>();
        QueryFmWorkVo queryCondition = vo.getEntity(QueryFmWorkVo.class);
        List<FmWorkVo> resultVoList = mapper.selectByCondition(queryCondition);
        return ResultUtil.success(result, resultVoList);
    }

    /**
     * 分区域按年份统计作业量
     *
     * @return
     */
//    @PostConstruct
//    @Scheduled(fixedRate = FarmSysConstant.SCHEDULE_FIX_RATE)
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse statisticWorkQuantityByAreaPerYear() {
        LocalDateTime currentDate = LocalDateTime.now(ZoneId.systemDefault());
        int year = currentDate.getYear();
        LocalDateTime queryBeginTime = currentDate.with(TemporalAdjusters.firstDayOfYear());
        LocalDateTime queryEndTime = currentDate.with(TemporalAdjusters.lastDayOfYear());
        if(currentDate.isBefore(queryEndTime)){
            queryEndTime = currentDate;
        }
        boolean redisFlag;
        int count;
        Map<String, String> sysJobTypeMap = FarmSysConstant.SYS_JOB_TYPE_MAP;
        QueryWrapper<FmCar> fmCarQueryWrapper;
        QueryFmWorkVo queryFmWorkVo;
        String officeCode, officeType,officeName;
        List<FmCar> fmCarList;
        List<TotalWorkQuantity> totalWorkQuantityList = Lists.newLinkedList();
        List<JsSysOffice> jsSysOfficeList = jsSysOfficeService.getAll();
        List<String> fmCarIdList = Lists.newLinkedList();
        List<StatisticByAreaAndWorkTypePerYear> statisticByAreaAndWorkTypePerYearList;
        if (CollectionUtils.isNotEmpty(jsSysOfficeList)) {
            String itemKey;
            String key = FarmSysConstant.REDIS_KEY_STATISTIC_TOTAL_WORK_QUANTITY;
            for (JsSysOffice jsSysOffice : jsSysOfficeList) {
                itemKey = jsSysOffice.getOfficeCode();
                totalWorkQuantityList.clear();
                fmCarIdList.clear();
                fmCarQueryWrapper = new QueryWrapper<>();
                queryFmWorkVo = new QueryFmWorkVo();
                queryFmWorkVo.setQueryBeginTime(queryBeginTime);
                queryFmWorkVo.setQueryEndTime(queryEndTime);
                officeCode = jsSysOffice.getOfficeCode();
                officeType = jsSysOffice.getOfficeType();
                officeName = jsSysOffice.getOfficeName();
                switch (officeType) {
                    case "1":
                        //省级机构区域
                        fmCarQueryWrapper.eq("province", officeCode);
                        break;
                    case "2":
                        //市级机构区域
                        fmCarQueryWrapper.eq("city", officeCode);
                        break;
                    case "3":
                        //区县级机构区域
                        fmCarQueryWrapper.eq("county", officeCode);
                        break;
                    default:
                        //乡镇级机构区域
                        fmCarQueryWrapper.eq("towns", officeCode);
                        break;
                }
                count = fmCarService.count(fmCarQueryWrapper);
                if (0 == count){
                    continue;
                }
                fmCarList = fmCarService.list(fmCarQueryWrapper);
                for (FmCar fmCar : fmCarList){
                    fmCarIdList.add(fmCar.getCarId());
                }
                queryFmWorkVo.setCarIdList(fmCarIdList);
                String workType, workTypeName;
                statisticByAreaAndWorkTypePerYearList = mapper.statisticByAreaAndWorkTypePerYear(queryFmWorkVo);
                if (CollectionUtils.isNotEmpty(statisticByAreaAndWorkTypePerYearList)){
                    for (StatisticByAreaAndWorkTypePerYear statisticVo : statisticByAreaAndWorkTypePerYearList){
                        TotalWorkQuantity totalWorkQuantity = new TotalWorkQuantity();
                        BeanUtils.copyProperties(statisticVo,totalWorkQuantity);
                        workType = statisticVo.getTypeCode();
                        workTypeName = sysJobTypeMap.get(workType);
                        totalWorkQuantity.setTypeName(workTypeName);
                        totalWorkQuantity.setAreaCode(officeCode);
                        totalWorkQuantity.setAreaName(officeName);
                        totalWorkQuantity.setStatisticYear(year);
                        totalWorkQuantity.setOwner(jsSysOffice.getParentCode());
                        totalWorkQuantityList.add(totalWorkQuantity);
                    }
                }
                if (CollectionUtils.isNotEmpty(totalWorkQuantityList)) {
                    redisFlag = redisUtils.hSet(key, itemKey, JSON.toJSONString(totalWorkQuantityList));
                    if (!redisFlag) {
                        throw new FarmException(CommonConstant.EX_DB_REDIS_ERROR, "系统缓存数据库异常");
                    }
                }
            }
        }
        return ResultUtil.success();
    }


    /**
     * 根据条件查询结果,并导出到Excel
     *
     * @param vo 查询条件
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResponse<String> exportExcel(BaseRequestVo<QueryFmWorkVo> vo) {
        RestResponse<String> result = new RestResponse<>();
        List<ExportFmWorkVo> resultList = Lists.newArrayList();
        RestResponse<List<FmWorkVo>> queryResult = getList(vo);
        List<FmWorkVo> voList = null;
        if (queryResult.isSuccess()) {
            voList = queryResult.getData();
        }
        if (CollectionUtils.isNotEmpty(voList)) {
            for (FmWorkVo temp : voList) {
                ExportFmWorkVo exportVo = new ExportFmWorkVo();
                BeanUtils.copyProperties(temp, exportVo);
                resultList.add(exportVo);
            }
        }
        String downLoadUrl;
        try {
            downLoadUrl = excelService.exportExcel(resultList, ExcelFileEnum.FM_WORK);
            if (StringHelper.isEmpty(downLoadUrl)) {
                return ResultUtil.success(result, downLoadUrl);
            }
        } catch (IOException e) {
            throw new FarmException(CommonConstant.EX_EXCEL_ERROR, e.getMessage());
        }
        return ResultUtil.success(result, downLoadUrl);
    }

    /**
     * 通用删除方法，包含批量删除与单条删除
     *
     * @param vo 删除条件
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse delete(@NotNull IdsVo vo) {
        if (ValidateUtils.isNullOrEmpty(vo.getId()) && CollectionUtils.isEmpty(vo.getIdsList())) {
            LOG.warn("FmWork delete params is null.", this.getClass().getSimpleName());
            return ResultUtil.error(CommonConstant.EX_FORM_VALIDATE_REQUIRED, "缺少必要的参数！");
        }
        List<Long> idsList = vo.getIdsList();
        if (CollectionUtils.isNotEmpty(idsList)) {
            //如果idList不为空，优先进行批量删除
            return deleteByIds(idsList);
        }
        Long id = vo.getId();
        return deleteById(id);
    }

    /**
     * 删除农机作业
     *
     * @param id 主键ID
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse deleteById(Long id) {
        boolean flag = removeById(id);
        if (!flag) {
            LOG.error("FmWork delete unsuccessful. id :{}", id);
            return ResultUtil.error(CommonConstant.EX_DB_DELETE_ERROR, "删除记录失败！");
        }
        return ResultUtil.success();
    }

    /**
     * 批量删除农机作业
     *
     * @param idList 主键ID列表
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse deleteByIds(List<Long> idList) {
        boolean flag = removeByIds(idList);
        if (!flag) {
            LOG.error("FmWork delete batch unsuccessful. ids :{}", idList);
            return ResultUtil.error(CommonConstant.EX_DB_DELETE_ERROR, "批量删除失败");
        }
        return ResultUtil.success();
    }

    /**
     * 逻辑校验规则
     *
     * @param entity       被校验的实体类
     * @param restResponse 消息传递对象
     * @return 结果
     */
    private RestResponse logicValidate(FmWork entity, RestResponse restResponse) {
        return ResultUtil.success(restResponse, null);
    }

    /**
     * 查询记录是否重复
     * 标准：编号
     *
     * @param number 唯一性条件
     * @return
     */
    private boolean isExist(String number) {
        if (StringHelper.isEmpty(number)) {
            return false;
        }
        int count = mapper.selectCount(new QueryWrapper<FmWork>().eq("number", number));
        return count > 0 ? true : false;
    }

    /**
     * ----------------------------- 分割线 以下是setter方法，用于替换field上的@Autowired -----------------------------
     **/

    @Autowired
    public void setMapper(FmWorkMapper mapper) {
        this.mapper = mapper;
    }

    @Autowired
    @Lazy
    public void setExcelService(IExcelService excelService) {
        this.excelService = excelService;
    }

    @Autowired
    @Lazy
    public void setCommonService(CommonService commonService) {
        this.commonService = commonService;
    }

    @Autowired
    @Lazy
    public void setJsSysOfficeService(IJsSysOfficeService jsSysOfficeService) {
        this.jsSysOfficeService = jsSysOfficeService;
    }

    @Autowired
    @Lazy
    public void setJsSysEmployeeService(IJsSysEmployeeService jsSysEmployeeService) {
        this.jsSysEmployeeService = jsSysEmployeeService;
    }

    @Autowired
    @Lazy
    public void setFmCarService(IFmCarService fmCarService) {
        this.fmCarService = fmCarService;
    }

    @Autowired
    @Lazy
    public void setRedisUtils(RedisUtils redisUtils) {
        this.redisUtils = redisUtils;
    }
}
